package com.lee.security.resources.manager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.util.AntPathMatcher;

import com.lee.security.entity.SysResource;
import com.lee.security.entity.SysRole;


/**
 * 最核心的地方，就是提供某个资源对应的权限定义，即getAttributes方法返回的结果。
 * 此类在初始化时，应该取到所有资源及其对应角色的定义。
 */
public class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource {
	
	/**
	 * 角色集合
	 */
	Collection<ConfigAttribute> allConfigAttributes = null;
			
	private JdbcTemplate jdbcTemplate;
	
	/**
	 * 资源集合，key为资源url，value为资源所需要的权限集合,即资源对应的角色集合
	 */
	private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

	public MyInvocationSecurityMetadataSourceService(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
		loadResourceDefine();
	}

	private void loadResourceDefine() {
		String sql = "SELECT role_id roleId, role_code roleCode FROM S_ROLES";
		List<SysRole> allRoles = jdbcTemplate.query(sql, new BeanPropertyRowMapper<SysRole>(SysRole.class));
		for (SysRole role : allRoles) {
			String roleId = role.getRoleId();
			String queryResourceByRoleId = "SELECT resource_id, resource_url, resource_name enabled FROM s_resources WHERE role_id = ?";
			List<SysResource> resources = jdbcTemplate.query(queryResourceByRoleId, new Object[]{roleId}, new BeanPropertyRowMapper<SysResource>(SysResource.class));
			role.setResources(resources);
		}

		/*
		 * 应当是资源为key， 权限为value。 资源通常为url， 权限就是那些以ROLE_为前缀的角色。
		 * 一个url(资源)可以由多个role_(权限)来访问，所以url对应权限集合,即 Collection<ConfigAttribute>
		 * 
		 * ConfigAttribute 相当于 角色 ROLE_
		 */
		allConfigAttributes = new ArrayList<ConfigAttribute>();
		resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
		for (SysRole role : allRoles) {
			String auth = role.getRoleCode();
			ConfigAttribute ca = new SecurityConfig(auth); // 相当于角色
			allConfigAttributes.add(ca);
			
			List<SysResource> resources = role.getResources();
			for (SysResource resource : resources) {
				String url = resource.getResourceUrl();
				/*
				 * 判断资源文件和权限的对应关系，如果已经存在相关的资源url，则要通过该url为key提取出权限集合，将权限增加到权限集合中
				 */
				if (resourceMap.containsKey(url)) {
					Collection<ConfigAttribute> value = resourceMap.get(url);
					value.add(ca);
					resourceMap.put(url, value);
				} else {
					Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
					atts.add(ca);
					resourceMap.put(url, atts);
				}
			}
		}
	}

	@Override
	public Collection<ConfigAttribute> getAllConfigAttributes() {
		return allConfigAttributes;
	}

	// 根据URL，找到相关的权限配置。
	@Override
	public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
		AntPathMatcher apm = new AntPathMatcher();
		Collection<ConfigAttribute> cac = null;
		// object 是一个URL，被用户请求的url。
		String url = ((FilterInvocation) object).getRequestUrl();

		/**
		 * 把url的请求参数去掉。例如 /user/add?name=libai ==> /user/add
		 */
		int firstQuestionMarkIndex = url.indexOf("?");
		if (firstQuestionMarkIndex != -1) {
			url = url.substring(0, firstQuestionMarkIndex);
		}

		Iterator<String> ite = resourceMap.keySet().iterator();
		while (ite.hasNext()) {
			String resURL = ite.next();
			if (apm.match(url, resURL)) {
				cac = resourceMap.get(resURL);
			}
		}
		
		return cac;
	}

	@Override
	public boolean supports(Class<?> arg0) {
		return true;
	}

	public static void main(String[] args) {
		AntPathMatcher apm = new AntPathMatcher();
		System.out.println(apm.match("/user/add", "/user/add"));
	}
}